home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / util / fixfd.1 < prev    next >
Internet Message Format  |  1989-02-03  |  31KB

  1. Path: xanth!ames!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i016:  fixfd - make asm include file from a .fd file
  5. Message-ID: <11545@swan.ulowell.edu>
  6. Date: 3 Feb 89 05:02:08 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1150
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: rick@QUCDNAST.BITNET
  12. Posting-number: Volume 89, Issue 16
  13. Archive-name: util/fixfd.1
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    ReadMe
  23. #    FixFD.asm
  24. #    FixFD.docs
  25. #    FixFD.link
  26. #    FixFD.uu
  27. #    Std_Start.uu
  28. # This archive created: Mon Jan 30 18:53:00 1989
  29. cat << \SHAR_EOF > ReadMe
  30.  
  31.  To : Aspiring M68000 Programmers
  32.  
  33. From: Peter Wyspianski
  34.  
  35. Date: 01 Jan 89
  36.  
  37.  
  38. As I was getting ready to archive my 'FixFD' utility, it occured to me that
  39. some aspects of programming the Amiga would have been a LOT easier to learn if
  40. I just had a few examples to look over.
  41.  
  42. I came to the Amiga programming enviroment from the MacIntosh.  So I was no
  43. stranger to the M68000 or the sort of things you have to do with it in such a
  44. complex enviroment.  Still, it has been a struggle.  While writing this utility
  45. I had to learn how to detect the user hitting 'ctrl-c' to abort the program. 
  46. No big deal, but I wasted a couple hours looking in the wrong places for the
  47. information (the AmigaDOS manual and some magazines).  Turns out it is not
  48. really documented anywhere, at least not specifically.
  49.  
  50. But I wonder where I would be now if I was a complete novice M68000 programmer?
  51. It's not like the 6502 days when you could just drop into a machine language
  52. monitor and hand-code some instructions to see what they do (that is how I
  53. first learned ML).
  54.  
  55. I have decided to include the source code for the main program.  You may study
  56. it, and even use the routines if you like.  I just hope you learn something.
  57.  
  58. I have NOT included my 'Std_Macs68k' file.  This file just contains a bunch of
  59. macros that match my programming style.  For example, if I am testing a
  60. register for zero, I like to be able to code 'bz.s xxx' rather then the more
  61. ambiguous 'beq.s xxx'.  So in my macro file I have a macro called 'bz'.
  62.  
  63. I have also not included the 'dos_lib.i' file.  This file can be created by
  64. using FixFD like so:
  65.  
  66. >FixFD dos_lib.fd dos_lib.i
  67.  
  68. in my case, I then edited the dos_lib.i file to add a 'PREASM' option and ran
  69. it through the assembler (CAPE68k from Inovatronics).  This feature of CAPE
  70. lets it inhale the 'INCLUDE' file without pausing to assemble it.  A real
  71. timesaver in larger projects.  This step is entirely optional.
  72.  
  73. Finally, the code must be linked with Std_Startup.obj.  This file is my
  74. customized version of AStartup.obj.  I have included 'Std_Startup.obj' but not
  75. the source code for it.  If you want to play around with FixFD, you could link
  76. with AStartup.obj instead.  Here is how you get the link to work:
  77.  
  78. >BLink with FixFD.link
  79.  
  80. if you don't happen to have the freely-redistributable 'BLink' then substitute
  81. the name of your linker (probably 'ALink').  The file 'FixFD.link' is also
  82. included.  Take a look at it, because it expects to find everything in 'RAM:'.
  83.  
  84. Good luck!  Remember to read the docs.  And if you have any questions or
  85. comments then please send me a postcard (my address is in the docs).
  86.  
  87. -Peter W.SHAR_EOF
  88. cat << \SHAR_EOF > FixFD.asm
  89. ; file:FixFD.asm
  90. ;-----------------------------
  91. ;          Fix FD
  92. ;-----------------------------
  93. ; A utility to convert FD files to EQU files.
  94. ;
  95. ; Copyright (c) 1988 by Peter Wyspianski
  96. ;
  97. ; Revision History
  98. ; ----------------
  99. ; 30 Dec 88  created
  100. ; 01 Jan 89  changed to use the 'dos_lib.i' file
  101.  
  102. ;----------------------------------------
  103. ; Constants
  104.  
  105. null    equ     $00
  106. bs    equ    $08
  107. tab    equ    $09
  108. lf    equ     $0a ; amiga eoln
  109. cr    equ     $0d ; CR only
  110. esc    equ    $1b
  111. csi    equ    $9b ; control sequence introducer
  112.  
  113. ; DOS Constants:
  114.  
  115. MODE_OLDFILE    equ 1005
  116. MODE_NEWFILE    equ 1006
  117.  
  118. SIGBREAKB_CTRL_C    EQU    $0C
  119. SIGBREAKB_CTRL_D    EQU    $0D
  120. SIGBREAKB_CTRL_E    EQU    $0E
  121. SIGBREAKB_CTRL_F    EQU    $0F
  122.  
  123. SIGBREAKF_CTRL_C    EQU    $1000
  124. SIGBREAKF_CTRL_D    EQU    $2000
  125. SIGBREAKF_CTRL_E    EQU    $4000
  126. SIGBREAKF_CTRL_F    EQU    $8000
  127.  
  128. ;**SIGBREAK_ANY        equ    $F000
  129. SIGBREAK_ANY        equ    $1000
  130.  
  131. ; Exec Base Offsets:
  132.  
  133. ThisTask    EQU    $114
  134.  
  135. ; Task Control Structure Offsets:
  136.  
  137. TC_SIGRECVD    EQU    $1A
  138. TC_SIGALLOC    EQU    $12
  139.  
  140. ;----------------------------------------
  141. ; Includes
  142.  
  143.     MACFILE "RAM:Std_Macs68k"
  144.     INCLUDE "RAM:dos_lib.i"
  145.  
  146. ;----------------------------------------
  147. ; Publics
  148.  
  149.     XDEF    _main
  150.     XDEF    Exit
  151.     
  152. ;----------------------------------------
  153. ; Externals:
  154.  
  155. ; from std.startup:
  156.  
  157.     XREF    _exit
  158.     XREF    _stdin,_stdout,_SysBase,_DOSBase
  159.  
  160. ;----------------------------------------
  161. ; The beginning
  162.  
  163.     SECTION Main,CODE
  164.  
  165. ; just a little something to brighten some file-zapper's day:
  166.  
  167.     dc.b    'Be Happy!',null
  168.     cnop    0,2
  169.  
  170. ;-------------------------------
  171. ; BCD_Left  [18 Nov 88]
  172. ;
  173. ; - converts hex word to a string of one to five left justified BCD digits
  174. ; - string is null terminated
  175. ;
  176. ; Inputs :  d0.w = hex word
  177. ;           a0.l = starting address of string
  178. ; Outputs:  all regs preserved
  179. ;
  180. ; Notes  :  - from 1 to five digits can be returned plus the zero termination
  181. ;             for a total of up to six characters
  182. ;           - starts by determining number of digits in the string
  183.  
  184. BCD_Left
  185.  
  186.     pushm    d0-d3/a0-a1
  187.     
  188.     move.w    #3,d2        ; # digits - 2
  189.     lea    LBCDTAB,a1    ; point to ten thousands
  190.  
  191. 1$    cmp.w    (a1)+,d0    ; determine number of digits in result
  192.     bcc.s    2$        ; (ubge) taken if right size
  193.     dbra    d2,1$        ; taken for 10K through 10
  194.     bra.s    6$        ; we have just a ones digit
  195.  
  196. 2$    subq.l    #2,a1        ; compensate for following pre-decrement
  197.  
  198. 3$    move.w    (a1)+,d1    ; d1=BCD digit weight
  199.     move.b    #'0',d3        ; init digit to ASCII '0'
  200. 4$    cmp.w    d1,d0        ; digit weight ? remainder
  201.     blt    5$        ; taken if done with this digit
  202.     addq.b    #1,d3        ; inc BCD digit result
  203.     sub.w    d1,d0        ; decrement total
  204.     bnz.s    4$        ; go for more
  205. 5$    move.b    d3,(a0)+    ; stash digit
  206.     dbra    d2,3$        ; next digit position
  207. 6$    or.b    #'0',d0        ; form ones digit
  208.     move.b    d0,(a0)+
  209.     clr.b    (a0)        ; form zero terminator
  210.  
  211.     pullm    d0-d3/a0-a1
  212.     rts
  213.  
  214. LBCDTAB    dc.w    10000,1000,100,10
  215.  
  216. ;----------------------------------------
  217. ; GetDec  [30 Dec 88]
  218. ;
  219. ; - converts a decimal string to a hex value
  220. ;
  221. ; Inputs : a0 = ^ string
  222. ; Outputs: d0.l = value
  223. ;
  224. ; Reg Use: d1,a0-a1
  225. ;
  226. ; Calls  : none
  227. ; Uses   : none
  228. ;
  229. ; Notes  : - Non-numeric input produces garbage (GIGO applies).
  230. ;       - Excessively long strings cause wrap-around.
  231.  
  232. GetDec:
  233.  
  234.     clr.l    d0        ; result
  235. 1$    move.b    (a0)+,d1    ; fetch next digit
  236.     bz.s    2$        ; if 'digit' is a null then all done
  237.  
  238. ; here the running result is multiplied by ten:
  239.  
  240.     asl.l    #1,d0        ; x2
  241.     move.l    d0,a1        ; save the x2 value (a1 = scratch)
  242.     asl.l    #2,d0        ; x4 x8
  243.     add.l    a1,d0        ; x8 + x2 = x10
  244.     
  245. ; the latest 'units' digit is added to the result:
  246.  
  247.     sub.b    #'0',d1        ; force digit to range 0-9
  248.     add.l    d1,d0        ; splice into result
  249.     bra.s    1$        ; and go for more!
  250.  
  251. 2$    rts
  252.  
  253. ;----------------------------------------
  254. ; PrStr   [31 Dec 88] _stdout
  255. ; FPrStr  [31 Dec 88] a file
  256. ;
  257. ; - sends a null terminated string to a file (_stdout)
  258. ;
  259. ; Inputs : a0 = ^string
  260. ;       a1 = file handle (FPrStr only)
  261. ;
  262. ; Outputs: none
  263. ;
  264. ; Calls  : Write    (DOS.Library)
  265. ; Uses   : _DOSBase (library base)
  266. ;       _stdout
  267. ;
  268. ; Notes  : exits via the call to Write
  269.  
  270. PrStr:
  271.     move.l    _stdout,a1
  272. FPrStr:
  273.     push.l    a1    ; save file handle
  274.  
  275.     move.l    a0,a1    ; find the string length
  276. 1$    tst.b    (a1)+
  277.     bnz.s    1$    ; loop until end of string
  278.     sub.l    a0,a1    ; start-end+1 = len+1
  279.     sub.l    #1,a1    ; fix the length
  280.  
  281.     pull.l    d1    ; recover file handle
  282.     move.l    a0,d2    ; ^buffer
  283.     move.l    a1,d3    ; length
  284.     move.l    _DOSBase,a6
  285.     jmp    _LVOWrite(a6)    ; exit via this routine
  286.  
  287. ;----------------------------------------
  288. ; ReadLn   [31 Dec 88] from _stdin
  289. ; FReadLn  [31 Dec 88] from a file
  290. ;
  291. ; - reads a line from a file (_stdin)
  292. ; - terminator (lf) is NOT stored
  293. ; - string is returned null-terminated
  294. ;
  295. ; Inputs : a0 = ^string buffer
  296. ;       a1 = file handle (FReadLn only)
  297. ;
  298. ; Outputs: d0 = result: 1 = ok, 0 = eof, -1 = error
  299. ;
  300. ; Reg Use: d0-d3/a0-a2
  301. ;
  302. ; Calls  : Read    (DOS.Library)
  303. ; Uses   : _DOSBase (library base)
  304.  
  305. ReadLn:
  306.     move.l    _stdin,a1
  307.  
  308. FReadLn:
  309.  
  310.     move.l    a0,a2        ; keep ^buffer safe
  311.     move.l    a1,a3        ; keep file handle safe
  312.     
  313. 1$    move.l    a3,d1        ; file handle
  314.     move.l    a2,d2        ; ^buffer
  315.     move.l    #1,d3        ; read one char
  316.     CallDOS    Read
  317.     cmp.l    #1,d0        ; what was returned?
  318.     bne.s    2$        ; exit if error or eof
  319.     
  320.     move.b    (a2)+,d1    ; fetch character and bump ^buffer
  321.     cmp.b    #lf,d1        ; end of line?
  322.     bne.s    1$        ; taken if not
  323.  
  324. 2$    move.b    #null,-1(a2)    ; null terminate the string
  325.     rts            ; and exit
  326.  
  327. ;----------------------------------------
  328. ; FileOpenError  [31 Dec 88]
  329. ;
  330. ; - calls IoErr to get a specific error number for a failed file open.
  331. ; - prints an error message of the form:
  332. ;
  333. ;   Error #xxx opening file "yyyy".
  334. ;
  335. ;
  336. ; Inputs : a0 = ^filename
  337. ; Outputs: none
  338. ;
  339. ; Reg Use: d0-d1/a0-a1
  340. ;
  341. ; Calls  : IoErr    (DOS.Library)
  342. ;       BCD_Left
  343. ;       PrStr
  344. ; Uses   : _DOSBase (library base)
  345. ;       BCDBuff
  346.  
  347. FileOpenError:
  348.  
  349.     push.l    a0        ; save ^file name
  350.  
  351.     CallDOS    IoErr        ; must do this FIRST
  352.     push.w    d0        ; save the bad news
  353.  
  354.     lea    BadOpenMsg,a0
  355.     jsr    PrStr
  356.  
  357.     pull.w    d0        ; recover error number
  358.     lea    BCDBuff,a0
  359.     jsr    BCD_Left
  360.     
  361.     lea    BCDBuff,a0
  362.     jsr    PrStr        ; show the number
  363.     
  364.     lea    BadOpenMsg1,a0    ; second half of error message
  365.     jsr    PrStr
  366.     
  367.     pull.l    a0        ; fetch ^file name
  368.     jsr    PrStr
  369.     
  370.     lea    BadOpenMsg2,a0    ; third half of error message
  371.     jsr    PrStr
  372.     
  373.     rts
  374.  
  375. *----------------------------------------
  376. * Main  [30 Dec 88]
  377. *
  378. * here is a picture of the entry stack:
  379. *
  380. *   12  ---        not ours!
  381. *    8  ^argvArray pointer to argvArray
  382. *    4  argc       argument count
  383. * sp 0  RA     our return address
  384.  
  385. _main:
  386.     clr.l    TheError    ; default good return
  387.     
  388.     move.l  sp,savesp    ; to ensure that we clean up on exit
  389.     pull.l    ReturnAddr    ; just in case we need it...
  390.  
  391. ; make a pointer to our TC_SIGRECVD:
  392.  
  393.     move.l    _SysBase,a0    ; base of the Exec library
  394.     move.l    ThisTask(a0),a0    ; ^Task Control Structure (that's us!)
  395.     lea    TC_SIGRECVD(a0),a0 ; ^the flags
  396.     move.l    a0,TaskSigs    ; save the pointer for later
  397.  
  398. ; and we're off:
  399.  
  400.     lea    GreetMsg,a0    ; say hello
  401.     jsr    PrStr
  402.  
  403.     pull.l    argc        ; argc (argument count)
  404.     pull.l    argv        ; ^argv (argument array)
  405.     
  406.     move.l    argc,d0        ; argv format: <name> <source> <dest>
  407.     cmp.l    #3,d0        ; we need three arguments...
  408.     blt.l    Help        ; ...taken if 'confused user' error!
  409.  
  410.     move.l    argv,a0        ; fetch ^argv
  411.     move.l    4(a0),a0    ; point to first argument
  412.     move.l    a0,SName    ; save ^source file name
  413.  
  414.     move.l    argv,a0        ; fetch ^argv
  415.     move.l    8(a0),a0    ; point to second argument
  416.     move.l    a0,DName    ; save ^dest file name
  417.  
  418. ; open the input file:
  419.  
  420.     move.l    SName,d1
  421.     move.l    #MODE_OLDFILE,d2    ; must already exist
  422.     CallDOS    Open
  423.  
  424.     move.l    d0,sfile    ; save source file handle
  425.     bnz.s    1$        ; taken if ok
  426.  
  427. ; handle problems opening the input file:
  428.  
  429.     move.l    SName,a0
  430.     jsr    FileOpenError
  431.     move.l    #30,TheError
  432.     bra.l    Exit            ; bye!
  433.  
  434. ; open the output file:
  435.  
  436. 1$    move.l    DName,d1
  437.     move.l    #MODE_NEWFILE,d2
  438.     CallDOS    Open
  439.  
  440.     move.l    d0,dfile    ; save dest file handle
  441.     bnz.s    ScanFD        ; taken if ok
  442.  
  443. ; handle problems opening the output file:
  444.  
  445.     move.l    DName,a0
  446.     jsr    FileOpenError
  447.     move.l    #30,TheError
  448.     bra.l    Exit2
  449.     
  450. ; read lines of the input file until EOF is true:
  451.  
  452. ScanFD:
  453.  
  454. ; If the output file is acutally the tube then we don't want
  455. ; line numbers cluttering the display:
  456.  
  457.     move.l    dfile,d1    ; output file handle
  458.     CallDOS    IsInteractive
  459.     move.b    d0,TubeOut    ; -1 = yeah, 0 = nope
  460.     
  461.     lea    HeaderMsg,a0
  462.     move.l    dfile,a1    ; output file handle
  463.     jsr    FPrStr
  464.  
  465.     move.l    DName,a0
  466.     move.l    dfile,a1    ; output file handle
  467.     jsr    FPrStr
  468.     
  469.     lea    HeaderMsg1,a0
  470.     move.l    dfile,a1    ; output file handle
  471.     jsr    FPrStr
  472.  
  473.     tst.b    TubeOut        ; skip screen formatting if outfile...
  474.     bnz.s    1$        ; ... is connected to the tube.
  475.     
  476.     lea    StatusMsg,a0
  477.     jsr    PrStr
  478.  
  479.     lea    CursorOff,a0
  480.     jsr    PrStr
  481.  
  482. 1$    move.w    line,d0        ; bump line number
  483.     add.w    #1,d0
  484.     move.w    d0,line
  485.  
  486.     tst.b    TubeOut        ; gonna use the tube?
  487.     bnz.s    8$        ; taken if not (being used by out file)
  488.  
  489.     lea    BCDBuff,a0    ; convert line number to a dec string
  490.     jsr    BCD_Left
  491.  
  492.     lea    BCDBuff,a0    ; show the line number
  493.     jsr    PrStr
  494.  
  495. ; This gets REAL fancy by adding one 'bs' to StrBuff for every
  496. ; non-null char in BCDBuff:
  497.  
  498.     lea    BCDBuff,a0
  499.     lea    StrBuff,a1
  500.     
  501. 2$    move.b    #bs,(a1)+    ; put one in there
  502.     tst.b    (a0)+        ; check for a null
  503.     bnz.s    2$        ; taken if not
  504.     
  505.     move.b    #null,-1(a1)    ; kill the last bs and null terminate
  506.  
  507.     lea    StrBuff,a0    ; backup
  508.     jsr    PrStr
  509.  
  510. 8$    move.l    TaskSigs,a0    ; see if the user hit ctrl-c thru ctrl-f
  511.     move.l    (a0),d0        ; d0 = SigsRecvd
  512.     and.l    #SIGBREAK_ANY,d0    ; mask all but ours
  513.     bnz.l    Abort        ; taken if we hit
  514.  
  515.     lea    StrBuff,a0    ; fetch a line from the input file
  516.     move.l    sfile,a1
  517.     jsr    FReadLn    
  518.  
  519.     tst.l    d0        ; see what's up!
  520.     
  521.     bz.l    Exit0        ; taken if EOF
  522.     bmi.l    Exit0        ; taken if error
  523.  
  524. ;----------------------------------------
  525. ; determine what sort of line it is here:
  526. ;
  527. ;         # = option (process further)
  528. ; A-Z,a-z,'_','.' = FD entry (strip)
  529. ;
  530. ; all others are ignored ('*',';', and anything else)
  531.  
  532.     move.b    StrBuff,d0    ; fetch first char
  533.     
  534.     cmp.b    #'#',d0        ; option?
  535.     beq    6$        ; taken if so
  536.     
  537.     cmp.b    #'.',d0        ; fd entry?
  538.     beq.s    3$        ; taken if so
  539.     
  540.     cmp.b    #'_',d0        ; fd entry?
  541.     beq.s    3$        ; taken if so
  542.     
  543.     cmp.b    #'A',d0        ; fd entry?
  544.     blt.l    1$        ; taken if NOT (ignore)
  545.     
  546.     or.b    #$20,d0        ; force to lowercase
  547.     cmp.b    #'z',d0        ; fd entry?
  548.     bgt.l    1$        ; taken if NOT (ignore)
  549.  
  550. ;---------------------------------------------------------------
  551. ; strip the line (scan for a space, open paren, or end of line)
  552. ; there are NO blank lines here (eliminated above):
  553. ;
  554.  
  555. 3$    lea    LVOMsg,a0    ; prefix the routine name with '_LVO'
  556.     move.l    dfile,a1
  557.     jsr    FPrStr
  558.     
  559.     lea    StrBuff,a0
  560. 5$    move.b    (a0)+,d0    ; fetch a char and bump pointer
  561.     bz.s    4$        ; taken if end of line
  562.     cmp.b    #' ',d0        ; space?
  563.     beq.s    4$        ; taken if so
  564.     cmp.b    #'(',d0        ; open paren?
  565.     bne.s    5$        ; taken if so
  566.  
  567. 4$    move.b    #null,-1(a0)    ; null-terminate right AT the 1st excess char
  568.  
  569.     pea    -1(a0)        ; save ^end of string (for later)
  570.     
  571.     lea    StrBuff,a0    ; show the line
  572.     move.l    dfile,a1    ; output file handle
  573.     jsr    FPrStr
  574.     
  575.     lea    StrBuff,a0
  576.     pull.l    d0        ; fetch ^end of string
  577. ;***    sub.l    a0,d0        ; d0 = string len
  578. ;***    lea    EQU8Msg,a0    ; <tab> <tab> equ <tab>-
  579. ;***    cmp.l    #8,d0        ; seven chars or less?
  580. ;***    blt.s    44$        ; taken if so (output extra tab)
  581.  
  582.     lea    EQUMsg,a0    ; <tab> equ <tab>-
  583. 44$    move.l    dfile,a1    ; output file handle
  584.     jsr    FPrStr
  585.     
  586.     move.w    bias,d0        ; convert the bias to a decimal string
  587.     lea    BCDBuff,a0
  588.     jsr    BCD_Left
  589.     
  590.     lea    BCDBuff,a0
  591.     move.l    dfile,a1    ; output file handle
  592.     jsr    FPrStr        ; show the bias
  593.  
  594.     lea    EQUMsg1,a0    ; finish the line off
  595.     move.l    dfile,a1    ; output file handle
  596.     jsr    FPrStr
  597.  
  598.     move.w    #6,d0        ; bump bias
  599.     add.w    d0,bias
  600.  
  601.     bra.l    1$        ; and go again!
  602.  
  603. ;----------------------------------------
  604. ; check for the '##bias' option:
  605.  
  606. 6$    move.l    StrBuff+2,d0    ; fetch 4 chars (should be 'bias')
  607.     or.l    #$20202020,d0    ; force to lowercase
  608.     cmp.l    #'bias',d0
  609.     bne.l    1$        ; ignore if not the option
  610.  
  611. ; scan for a space:
  612.  
  613.     lea    StrBuff+6,a0    ; skip the '##bias'
  614.  
  615. 7$    move.b    (a0)+,d0    ; fetch a char and bump pointer
  616.     bz.l    1$        ; taken if end of line (ignore)
  617.     cmp.b    #' ',d0        ; space?
  618.     bne.s    7$        ; taken if not
  619.  
  620. ; fetch and show the bias:
  621.  
  622.     jsr    GetDec        ; a0 should be pointing at the number
  623.     move.w    d0,bias        ; save it
  624.     
  625. ; show the 'bias = ' message:
  626.  
  627.     lea    BiasMsg,a0
  628.     move.l    dfile,a1    ; output file handle
  629.     jsr    FPrStr
  630.  
  631.     move.w    bias,d0        ; convert the bias to a decimal string
  632.     lea    BCDBuff,a0
  633.     jsr    BCD_Left
  634.     
  635.     lea    BCDBuff,a0
  636.     move.l    dfile,a1    ; output file handle
  637.     jsr    FPrStr        ; show the bias
  638.  
  639.     lea    BiasMsg1,a0
  640.     move.l    dfile,a1    ; output file handle
  641.     jsr    FPrStr
  642.     
  643.     bra.l    1$        ; go for another line
  644.  
  645.  
  646. ;-------------------------------------------
  647. ; show the help message and exit:
  648.  
  649. Help:
  650.     lea    HelpMsg,a0
  651.     jsr    PrStr
  652.     bra.s    Exit
  653.  
  654. ;-------------------------------------------
  655. ; show the 'break...' message and exit:
  656.  
  657. Abort:
  658.     lea    BreakMsg,a0
  659.     jsr    PrStr
  660.     bra.s    ExitA
  661.  
  662. ;-----------------------------
  663. ; Exit routines  [30 Dec 88]
  664. ;
  665.  
  666. Exit0:
  667.  
  668.     lea    DoneMsg,a0
  669.     jsr    PrStr
  670.  
  671. ExitA:
  672.     lea    CursorOn,a0
  673.     jsr    PrStr
  674.  
  675. Exit1:
  676.     move.l    dfile,d1    ; close the dest file
  677.     CallDOS    Close
  678.  
  679. Exit2:
  680.     move.l    sfile,d1    ; close the source file
  681.     CallDOS    Close
  682.  
  683. Exit:
  684.     push.l    TheError    ; error code
  685.     jsr    _exit        ; and wind it up
  686.  
  687. ;----------------------------------------
  688. ; constants
  689.  
  690.     SECTION Constants,DATA
  691.  
  692. GreetMsg:
  693.     dc.b    lf
  694.     dc.b    csi,'0;33;40m'
  695.     dc.b    ' FixFD '
  696.     dc.b    csi,'0;31;40m'
  697.     dc.b    'v1.0 - Copyright ',$a9
  698.     dc.b    ' 1988, Peter Wyspianski',lf,lf
  699.     dc.b    null
  700.  
  701. HelpMsg
  702.     dc.b    ' This utility takes an ''.FD'' file and generates a set of',lf
  703.     dc.b    ' EQUates that can be used by an assembler.',lf,lf
  704.     dc.b    ' Parameters: source_file dest_file.',lf,lf
  705.     dc.b    ' See the docs for more info! -PW',lf,lf,null
  706.  
  707. BadOpenMsg:
  708.     dc.b    csi,'0;33;40m'
  709.     dc.b    ' Error '
  710.     dc.b    csi,'0;31;40m'
  711.     dc.b    '#'
  712.     dc.b    null
  713.  
  714. BadOpenMsg1:
  715.     dc.b    ' opening file "',null
  716.  
  717. BadOpenMsg2:
  718.     dc.b    '"',lf,lf,null
  719.  
  720. CursorOff
  721.     dc.b    csi
  722.     dc.b    '0 p'
  723.     dc.b    null
  724.  
  725. CursorOn
  726.     dc.b    csi
  727.     dc.b    ' p'
  728.     dc.b    null
  729.  
  730. StatusMsg:
  731.     dc.b    '   Reading line '
  732.     dc.b    null
  733.  
  734. DoneMsg
  735.     dc.b    lf,lf
  736.     dc.b    csi,'0;33;40m'
  737.     dc.b    ' Finished.'
  738.     dc.b    csi,'0;31;40m'
  739.     dc.b    lf,lf,null
  740.  
  741. BreakMsg
  742.     dc.b    lf,lf
  743. ;***    dc.b    csi,'0;33;40m'
  744.     dc.b    '*** BREAK'
  745. ;***    dc.b    csi,'0;31;40m'
  746.     dc.b    lf,lf,null
  747.     
  748. HeaderMsg
  749.     dc.b    '; file:',null
  750.  
  751. HeaderMsg1
  752.     dc.b    lf
  753.     dc.b    ';',lf
  754.     dc.b    '; generated by FixFD v1.0',lf
  755.     dc.b    ';',lf
  756.     dc.b    null
  757.  
  758. BiasMsg
  759.     dc.b    '; Bias = ',null
  760.     
  761. BiasMsg1
  762.     dc.b    lf
  763.     dc.b    ';',lf
  764.     dc.b    null
  765.  
  766. LVOMsg
  767.     dc.b    '_LVO',null
  768.     
  769. EQU8Msg
  770.     dc.b    tab
  771. EQUMsg
  772.     dc.b    tab
  773.     dc.b    'equ -'
  774.     dc.b    null
  775.  
  776. EQUMsg1
  777.     dc.b    lf
  778.     dc.b    null
  779.  
  780. ;----------------------------------------
  781. ; Uninitialized storage
  782.  
  783.     SECTION Variables,BSS
  784.  
  785. TaskSigs    ds.l    1    ; pointer to our TC_SIGRECVD
  786.  
  787. TheError    ds.l    1    ; error return code
  788.  
  789. SName        ds.l    1    ; ^source file name
  790. DName        ds.l    1    ; ^dest file name
  791.  
  792. sfile        ds.l    1    ; source file handle
  793. dfile        ds.l    1    ; dest file handle
  794.  
  795. savesp        ds.l    1    ; entry stack pointer
  796.  
  797. argc        ds.l    1    ; argument count
  798. argv        ds.l    1    ; argument array pointer
  799.  
  800. ReturnAddr    ds.l    1    ; program return address
  801.  
  802. bias        ds.w    1    ; library entry bias
  803. line        ds.w    1    ; current line number
  804.  
  805. TubeOut        ds.b    1    ; -1 = yes, 0 = nope
  806.         ds.b    1    ; alignment
  807.  
  808. BCDBuff        ds.b    6    ; bcd string buffer
  809.  
  810. StrBuff        ds.b    256    ; longest possible string
  811.  
  812.         ENDSHAR_EOF
  813. cat << \SHAR_EOF > FixFD.docs
  814.  
  815.  FixFD v1.0
  816.  User Manual
  817.  
  818. Copyright (C) 1988 by Peter Wyspianski
  819.  
  820. [31 Dec 88]
  821.  
  822.  
  823. ----------------------
  824. Please Read The Manual
  825. ----------------------
  826.  
  827. The FixFD utility is not complicated, but please take a couple minutes to read
  828. through this manual before you try it.  Thanks!
  829.  
  830.  
  831. --------
  832. Abstract
  833. --------
  834.  
  835. FixFD is a utility for the Amiga series of computers that reads an '.FD' file
  836. to produce an assembler 'include' file.
  837.  
  838.  
  839. -----------
  840. Legal Stuff
  841. -----------
  842.  
  843. Amiga is a trademark of Commodore-Amiga, Inc.
  844. The author is in no way connected with Commodore-Amiga, Inc.
  845.  
  846. The FixFD utility package, consisting of the program and documentation file, is
  847. copyrighted.  Permission is granted for NON-COMMERCIAL distribution of
  848. UNMODIFIED copies of the entire package.  All other rights are reserved. 
  849. Distribution of separate parts of the package, or of modified copies is
  850. specifically prohibited.  Failure to abide by these rules may result in a fine,
  851. and/or jail term.  Additionally you may get a guilty conscience and I certainly
  852. won't visit you.  Pass the word, pass this program!
  853.  
  854.  
  855. -----------------------
  856. Who Needs This Utility?
  857. -----------------------
  858.  
  859. If you are an Amiga assembly language programmer (or want to be), then read on.
  860. Otherwise, this utility is NOT for you (sorry)!
  861.  
  862.  
  863. -----------
  864. The Problem
  865. -----------
  866.  
  867. When you're programming in assembly language, the most common way to define a
  868. 'Library Vector Offset' (LVO) is to use the XLIB macro like so:
  869.  
  870.     XLIB    Open    ; DOS.Library
  871.     XLIB    Close    ; DOS.Library
  872.     
  873. where the 'XLIB' macro looks something like this:
  874.  
  875. XLIB    macro        ; <routine name>
  876.     xref    _LVO\1
  877.     endm
  878.  
  879. so by the time the assembler has sorted out those first couple of definitions
  880. here is what you got:
  881.  
  882.     xref    _LVOOpen
  883.     xref    _LVOClose
  884.     
  885. Later on in the program you may want to call the 'Open' routine:
  886.  
  887.     move.l    DOSBase,a6
  888.     jsr    _LVOOpen(a6)
  889.  
  890. Of course most of us use a macro for those lines.  But here is a question -
  891. just where IS the actual value of the symbol '_LVOOpen' defined?  It is defined
  892. in the scanned library 'Amiga.Lib'!
  893.  
  894. The problem is that Amiga.Lib is about 80K bytes long, and contains a LOT of
  895. things besides the _LVO definitions.  Having the _LVOs defined in Amiga.Lib
  896. requires that you ALWAYS link your code with Amiga.Lib.  This effectively
  897. neutralizes assemblers that produce loadable object files.  It also makes for
  898. some very long link times.
  899.  
  900.  
  901. ------------
  902. The Solution
  903. ------------
  904.  
  905. The ideal solution to the problem of having the LVOs defined in Amiga.Lib is to
  906. just equate them to their proper values:
  907.  
  908. _LVOOpen    EQU    -30
  909. _LVOClose    EQU    -36
  910.  
  911. Now you don't have to link with Amiga.Lib and the assembler will probably get
  912. done a bit sooner as it doesn't have to do as much work.  To get these equates
  913. you simply use FixFD!
  914.  
  915.  
  916. ------------
  917. What It Does
  918. ------------
  919.  
  920. The Extras disk includes a drawer called 'FDx.x' (where x.x is the operating
  921. system revision, currently '1.3'.  Within this drawer are a number of files
  922. whose names end with '.FD'.  These '.FD' files all have a standard format. 
  923. They completely define all the LVOs within a particular library.  The '.FD'
  924. files are updated with every new revision of the operating system.
  925.  
  926. FixFD simply reads an '.FD' format file and cranks out a file that your
  927. assembler can read (using 'INCLUDE').  And thats all there is to it!
  928.  
  929. You have a lot of choices when it comes to putting the resultant 'include'
  930. files to use.  Adding a bunch of 'INCLUDE' statements is one possibility.  Or
  931. you could merge them into one big include file.  If your assembler supports
  932. 'preassembled symbols' then you can preassemble the LVO file(s) for lightning
  933. assembly speed!
  934.  
  935. I like to have all the LVOs in one big file.  That way I can use the cut-and-
  936. paste features of my text editor to put just the LVOs I need right into the
  937. assembly file I'm working on.
  938.  
  939. There is probably a utility somewhere out there that does exactly the same
  940. thing as FixFD.  Too bad I haven't seen it (yet)!  So here is my contribution. 
  941. Incidentally, it would have been far quicker to write this in something like
  942. BASIC, but I simply wanted some practice at working with DOS files from
  943. assembly.
  944.  
  945.  
  946. -----------
  947. Using FixFD
  948. -----------
  949.  
  950. From the CLI (Command Line Interpreter) or Shell type:
  951.  
  952. >fixfc source_file dest_file
  953.  
  954. where 'source_file' is the name of the '.FD' file you want to read
  955.  and   'dest_file'  is the name of the new file you want to make
  956.  
  957. You can use an asterix ('*') for the dest file, to send output to the CLI
  958. window.  In that case the fancy line number display is suppressed so it doesn't
  959. tangle up the output.
  960.  
  961. FixFD can be aborted in the usual way (ctrl-c).  And if you forget one of the
  962. file names (or use '?'), you get a little blurb reminding you what to do.
  963.  
  964. It DOESN'T work from WorkBench so don't try it (crashes the system).  I could
  965. make it WorkBench compatible but why bother?
  966.  
  967. Thats about it.  I sure hope you like it!
  968.  
  969.  
  970. --------------------
  971. So How Does It Work?
  972. --------------------
  973.  
  974. [This section is for the curious; it may be safely skipped by others.]
  975.  
  976.  
  977. FixFD scans each line of the input file looking for one of the following:
  978.  
  979. ##bias xx
  980.  
  981. Where xx is a decimal number 0-65535.  Sets the base from which subsequent LVOs
  982. are calculated.  Defaults to zero.  The usual value is 30.
  983.  
  984. <LVO name> <whatever>
  985.  
  986. An LVO name is any line that starts with one of these characters:
  987.  
  988.     a-z, A-Z, period ('.'), underline ('_')
  989.     
  990. When an LVO name is found, the line is scaned for an open paren ('(') or space.
  991. If one is found, the line is chopped from that point on.  In any case, the LVO
  992. name is written to the dest file with the prefix '_LVO'.  Following the name is
  993. a tab, the word 'equ', another tab, and the decimal offset of the LVO.
  994.  
  995. All other lines (including blank lines, and lines beginning with ';' or '*')
  996. are ignored.
  997.  
  998.  
  999. -------------------------
  1000. Send Postcards Not Money!
  1001. -------------------------
  1002.  
  1003. The Author enjoys getting mail.  Especially picture post cards.  If you like
  1004. this program, hate it, or want to see some improvements, please send me a
  1005. post card:
  1006.  
  1007. Peter Wyspianski
  1008. 5-10A Brock Cres
  1009. Kingston, Ont
  1010. CANADA  K7K 5K6
  1011.  
  1012. Don't bother sending money.  However, all offers of employment will be
  1013. seriously considered.
  1014.  
  1015.  
  1016. -----------------
  1017. End of the Manual
  1018. -----------------
  1019.  
  1020. Congradulations on having read this far.  Current research indicates that you
  1021. are one of only 9.23% of users who bother to read the manual.
  1022.  
  1023.  
  1024. -------------------------
  1025. Technical Details/Credits
  1026. -------------------------
  1027.  
  1028. FixFD is written in M68000 Assembly Language.  Total development time was about
  1029. eight hours, including writing this doc file.  I had to write most of the DOS
  1030. file code from scratch.  I already had the decimal conversion and formatting
  1031. routines.
  1032.  
  1033. Some of the better products used in the development of this utility include:
  1034.  
  1035. CAPE 68010 Assembler (Inovatronics)
  1036. BLink (Software Distillery)
  1037. Uedit (Rick Stiles)
  1038.  
  1039. (The preceeding was an unsolicited endorsement).
  1040.  
  1041. Special Thanks: Sharon W.
  1042.  
  1043.  
  1044.  
  1045. SHAR_EOF
  1046. cat << \SHAR_EOF > FixFD.link
  1047.  
  1048. FROM
  1049. RAM:Std_Startup.obj
  1050. RAM:FixFD.obj
  1051.  
  1052. TO
  1053. FixFD
  1054.  
  1055. SHAR_EOF
  1056. cat << \SHAR_EOF > FixFD.uu
  1057.  
  1058. begin 644 FixFD
  1059. M```#\P`````````&``````````4```!R````#@```&````$G````;````$T`"
  1060. M``/I````<B//````'"/`````)"/(````*$*Y````("QX``0CS@````23R4ZN6
  1061. M_MHH0$JL`*QG``"P80`!<B!L`*S1R-'((&@`$-'(T<A(YR`P1?D```"`1_D`^
  1062. M````=`%P`!`8)LI@`A384<C__$(:(#D````D('D````H$AA3@&\>#`$`(&_T3
  1063. M4H(FRF`*$AA3@`P!`"!O!!3!8/)"&F#<0AI"FR`"3-\,!$AY`````"\`+'D`U
  1064. M```(3J[_RB/`````$"QY````"$ZN_\0CP````!0CP````!A.N0```1QP`"YY9
  1065. M````'$YU80``Q&$``*XCP````"!"IR\`)$`@*@`D9Q`L>0````@@0"(H``!.<
  1066. MKO^"(BH`(&<H)#P```/M3J[_XB/`````$"/`````%"/`````&&<*Y8@@0"EH+
  1067. M``@`I$ZY```!''``8`0@+P`$+GD````<+P`L>``$(#D````(9P(B0$ZN_F)*C
  1068. MN0```"!G#DZN_WPB>0```"!.KOZ&(!].=4CG`08N/``#@`<L>``$3J[_E$S?.
  1069. M8(!P9&"R0>P`7$ZN_H!![`!<3J[^C$YU0KD````(0_D````L(#P````B3J[]]
  1070. MV"/`````"&>V3G4``````^P````9`````0````(````(````#@```!0````>V
  1071. M````:@```'````"L````M@```+P```#&````S````-H```#J````_````1P`G
  1072. M``$B```!*````4@```%4```!8@```6X```&H```!K@```;X````#`````@``8
  1073. M`$P```!2````I`````(````#````T@```3H````````#\@```^H````.``$`%
  1074. M``````````````````````````````````````````````````````!D;W,NT
  1075. M;&EB<F%R>0````/R```#ZP```&````/R```#Z0```2="92!(87!P>2$`2.?P*
  1076. MP#0\``-#^0```$JP660&4<K_^F`:58DR&18\`#"P06T```A2`Y!!9O00PU'*Y
  1077. M_^H````P$,!"$$S?`P].=2<0`^@`9``*0H`2&&<0XX`B0.6`T(D$`0`PT(%@7
  1078. M[$YU(GD````4+PDB2$H99OR3R)/\`````2(?)`@F"2QY````"$[N_]`B>0``?
  1079. M`!`D2"9)(@LD"B8\`````2QY````"$ZN_]8,@`````%F"!(:#`$`"F;<%7P`X
  1080. M`/__3G4O""QY````"$ZN_WP_`$'Y````\TZY````:C`?0?D````N3KD````*!
  1081. M0?D````N3KD```!J0?D```$.3KD```!J(%].N0```&I!^0```1Y.N0```&I.;
  1082. M=4*Y````!"//````&"/?````)"!Y````!"!H`11!Z``:(\@`````0?D`````&
  1083. M3KD```!J(]\````<(]\````@(#D````<#(`````#;0`"TB!Y````("!H``0C>
  1084. MR`````@@>0```"`@:``((\@````,(CD````()#P```/M+'D````(3J[_XB/`P
  1085. M````$&8:('D````(3KD```#&(_P````>````!&```LXB.0````PD/````^XL3
  1086. M>0````A.KO_B(\`````49AH@>0````Q.N0```,8C_````!X````$8``"AB(Y+
  1087. M````%"QY````"$ZN_R@3P````"Q!^0```6LB>0```!1.N0```'`@>0````PBV
  1088. M>0```!1.N0```'!!^0```7,B>0```!1.N0```'!*.0```"QF&$'Y```!*TZYR
  1089. M````:D'Y```!(DZY````:C`Y````*@9```$SP````"I*.0```"QF/D'Y````\
  1090. M+DZY````"D'Y````+DZY````:D'Y````+D/Y````-!+\``A*&&;X$WP``/__3
  1091. M0?D````T3KD```!J('D`````(!`"@```$`!F``%\0?D````T(GD````03KD`]
  1092. M``"62H!G``%R:P`!;A`Y````-`P``"-G``#$#```+F<:#```7V<4#```06T`&
  1093. M_UP````@#```>FX`_U!!^0```:$B>0```!1.N0```'!!^0```#00&&<,#```5
  1094. M(&<&#```*&;P$7P``/__2&C__T'Y````-")Y````%$ZY````<$'Y````-"`?1
  1095. M0?D```&G(GD````43KD```!P,#D````H0?D````N3KD````*0?D````N(GD`5
  1096. M```43KD```!P0?D```&N(GD````43KD```!P,#P`!M%Y````*&``_JX@.0``C
  1097. M`#8`@"`@("`,@&)I87-F`/Z80?D````Z$!AG`/Z,#```(&;T3KD```!2,\``\
  1098. M```H0?D```&3(GD````43KD```!P,#D````H0?D````N3KD````*0?D````N.
  1099. M(GD````43KD```!P0?D```&=(GD````43KD```!P8`#^+D'Y````1DZY````W
  1100. M:F!&0?D```%=3KD```!J8`Q!^0```3Q.N0```&I!^0```2=.N0```&HB.0``;
  1101. M`!0L>0````A.KO_<(CD````0+'D````(3J[_W"\Y````!$ZY```!0@`````#`
  1102. M[`````$````````$E@````L````!```!,````)(```"(````I@```,H```&8G
  1103. M```!T````@(```1V```$A@```&P````B`````P```!0```#<````Z@```/8`Z
  1104. M``$"```!"@```18```%*```!L````>@```(>```",````D(```)6```"8@``<
  1105. M`H8```*2```"N````MP```,F```#6````W(```.$```#E@```Z@```/D```#B
  1106. M_```!`X```0@```$,@``!$(```10```$7@``!&H````1````!````-8```#\Y
  1107. M```!$````40```(2```"-@```E````)<```#&@```V8```.<```#\```!"8`4
  1108. M``0\```$2@``!%@```1D````0`````4```#D````\````1X```$D```!*@``:
  1109. M`3X```%0```!5@```5P```%L```!=@```7P```&&```!C````:(```&J```!(
  1110. MN@```<0```':```!X@```?(```'\```"#````A@```(D```"*@```CP```)(O
  1111. M```":````G(```)X```"@````HP```*8```"G@```K(```*^```"T````M8``
  1112. M``+L```#(````RP```-,```#4@```UX```-L```#>````WX```.*```#D```0
  1113. M`Z(```.R```#O````](```/J```#]@``!`(```0(```$%```!!H```0L```$0
  1114. M<```!(````20`````````_(```/J````;`J;,#LS,SLT,&T@1FEX1D0@FS`[/
  1115. M,S$[-#!M=C$N,"`M($-O<'ER:6=H=""I(#$Y.#@L(%!E=&5R(%=Y<W!I86YSH
  1116. M:VD*"@`@5&AI<R!U=&EL:71Y('1A:V5S(&%N("<N1D0G(&9I;&4@86YD(&=E@
  1117. M;F5R871E<R!A('-E="!O9@H@15%5871E<R!T:&%T(&-A;B!B92!U<V5D(&)YL
  1118. M(&%N(&%S<V5M8FQE<BX*"B!087)A;65T97)S.B!S;W5R8V5?9FEL92!D97-T]
  1119. M7V9I;&4N"@H@4V5E('1H92!D;V-S(&9O<B!M;W)E(&EN9F\A("U05PH*`)LPB
  1120. M.S,S.S0P;2!%<G)O<B";,#LS,3LT,&TC`"!O<&5N:6YG(&9I;&4@(@`B"@H`8
  1121. MFS`@<`";('``("`@4F5A9&EN9R!L:6YE(``*"ILP.S,S.S0P;2!&:6YI<VAEZ
  1122. M9"Z;,#LS,3LT,&T*"@`*"BHJ*B!"4D5!2PH*`#L@9FEL93H`"CL*.R!G96YE%
  1123. M<F%T960@8GD@1FEX1D0@=C$N,`H["@`[($)I87,@/2``"CL*`%],5D\`"0EE]
  1124. 7<74@+0`*`````_(```/K````30```_([=
  1125. ``
  1126. end
  1127. size 2948
  1128. SHAR_EOF
  1129. cat << \SHAR_EOF > Std_Start.uu
  1130.  
  1131. begin 644 Std_Startup.obj
  1132. M```#YP````````/H`````E-T87)T=7`````#Z0```'(CSP```!PCP````"0C@
  1133. MR````"A"N0```"`L>``$(\X````$D\E.KO[:*$!*K`"L9P``L&$``7(@;`"L%
  1134. MT<C1R"!H`!#1R-'(2.<@,$7Y````@$?Y`````'0!<``0&";*8`(4V%'(__Q":
  1135. M&B`Y````)"!Y````*!(84X!O'@P!`"!O]%*")LI@"A(84X`,`0`@;P04P6#RD
  1136. M0AI@W$(:0IL@`DS?#`1(>0`````O`"QY````"$ZN_\HCP````!`L>0````A.^
  1137. MKO_$(\`````4(\`````83KD`````<``N>0```!Q.=6$``,1A``"N(\`````@7
  1138. M0J<O`"1`("H`)&<0+'D````(($`B*```3J[_@B(J`"!G*"0\```#[4ZN_^(C`
  1139. MP````!`CP````!0CP````!AG"N6(($`I:``(`*1.N0````!P`&`$("\`!"YY2
  1140. M````'"\`+'@`!"`Y````"&<"(D!.KOYB2KD````@9PY.KO]\(GD````@3J[^_
  1141. MAB`?3G5(YP$&+CP``X`'+'@`!$ZN_Y1,WV"`<&1@LD'L`%Q.KOZ`0>P`7$ZNB
  1142. M_HQ.=4*Y````"$/Y````+"`\````(DZN_=@CP`````AGMDYU``````/L````!
  1143. M&0````$````"````"`````X````4````'@```&H```!P````K````+8```"\<
  1144. M````Q@```,P```#:````Z@```/P```$<```!(@```2@```%(```!5````6(`\
  1145. M``%N```!J````:X```&^`````P````(```!,````4@```*0````````#[X$``
  1146. M``)?;6%I;@````````(```#2```!.@$```)?<W1A<G1U<``````!```"7V5X)
  1147. M:70```````%"`````````_(```/J````#@`!````````````````````````1
  1148. M````````````````````````````````9&]S+FQI8G)A<GD````#[P$```)?]
  1149. M<W1D97)R`````!@!```"7W-T9&]U=``````4`0```E]$3U-"87-E````"`$`1
  1150. M``)?<W1D:6X``````!`!```"7V5R<FYO```````,`0```E]3>7-"87-E````#
  1151. 5!`````````/R```#ZP```&````/R\
  1152. ``
  1153. end
  1154. size 876
  1155. SHAR_EOF
  1156. #    End of shell archive
  1157. exit 0
  1158. -- 
  1159. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1160. Have five nice days.
  1161.